package cn.bugstack.xfg.dev.tech.trigger.http;

import cn.bugstack.xfg.dev.tech.api.IRAGService;
import cn.bugstack.xfg.dev.tech.api.response.Response;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.redisson.api.RList;
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.ollama.OllamaChatClient;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.PgVectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.core.io.PathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;


@Slf4j
@RestController()
@CrossOrigin("*")
@RequestMapping("/api/v1/rag/")
public class RAGController implements IRAGService {

    @Resource
    private OllamaChatClient ollamaChatClient;
    @Resource
    private TokenTextSplitter tokenTextSplitter;
    @Resource
    private SimpleVectorStore simpleVectorStore;
    @Resource
    private PgVectorStore pgVectorStore;
    @Resource
    private RedissonClient redissonClient;

    @RequestMapping(value = "query_rag_tag_list", method = RequestMethod.GET)
    @Override
    public Response<List<String>> queryRagTagList() {
        RList<String> elements = redissonClient.getList("ragTag");
        return Response.<List<String>>builder()
                .code("0000")
                .info("调用成功")
                .data(elements)
                .build();
    }

    @RequestMapping(value = "file/upload", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
    @Override
    public Response<String> uploadFile(@RequestParam("ragTag") String ragTag, @RequestParam("file") List<MultipartFile> files) {
        log.info("上传知识库开始 {}", ragTag);
        for (MultipartFile file : files) {
            TikaDocumentReader documentReader = new TikaDocumentReader(file.getResource());
            // documents 可能包含两个 Document 对象，每个对象分别对应 PDF 文件中的一个章节。
            List<Document> documents = documentReader.get();
            //tokenTextSplitter 可能将每个章节进一步分割成更小的段落或固定长度的文本块。
            //documentSplitterList 可能包含多个 Document 对象，每个对象代表一个段落或文本块。
            List<Document> documentSplitterList = tokenTextSplitter.apply(documents);

            documents.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));
            documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", ragTag));

            pgVectorStore.accept(documentSplitterList);

            RList<String> elements = redissonClient.getList("ragTag");
            if (!elements.contains(ragTag)) {
                elements.add(ragTag);
            }
        }

        log.info("上传知识库完成 {}", ragTag);
        return Response.<String>builder().code("0000").info("调用成功").build();
    }

    /**
     * 根据 git 仓库地址，拉取代码，解析代码，上传知识库
     */
//    @RequestMapping(value = "analyze_git_repository", method = RequestMethod.POST)
//    @Override
//    public Response<String> analyzeGitRepository(String repoUrl, String userName, String token) throws Exception {
//        // 创建本地临时目录
//        String localPath = "./git-cloned-repo";
//        // 提取项目名
//        String repoProjectName = extractProjectName(repoUrl);
//        log.info("克隆路径：{}", new File(localPath).getAbsolutePath());
//        // 先递归删除./git-cloned-repo目录
//        FileUtils.deleteDirectory(new File(localPath));
//
//        log.info("git仓库地址：{}", repoUrl);
//        Git git = Git.cloneRepository()
//                .setURI(repoUrl)
//                .setDirectory(new File(localPath))
//                .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, token))
//                .call();
//
//        Files.walkFileTree(Paths.get(localPath), new SimpleFileVisitor<Path>() {
//            @Override
//            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//                // 只处理.java文件
//                if (file.toString().endsWith(".java")) {
//                    TikaDocumentReader documentReader = new TikaDocumentReader(new PathResource(file));
//                    List<Document> documents = documentReader.get();
//                    List<Document> documentSplitterList = tokenTextSplitter.apply(documents);
//                    documents.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));
//                    documentSplitterList.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));
//                    pgVectorStore.accept(documentSplitterList);
//                }
//                return FileVisitResult.CONTINUE;
//            }
//
//            @Override
//            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
//                if (dir.toString().endsWith("target")) {
//                    return FileVisitResult.SKIP_SUBTREE;
//                }
//                return FileVisitResult.CONTINUE;
//            }
//
//            @Override
//            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
//                return FileVisitResult.CONTINUE;
//            }
//        });
//
//        // 将克隆下面的目录写入向量库中之后，再次递归删除./git-cloned-repo目录
//        FileUtils.deleteDirectory(new File(localPath));
//
//        RList<String> elements = redissonClient.getList("ragTag");
//        if (!elements.contains(repoProjectName)) {
//            elements.add(repoProjectName);
//        }
//        git.close();
//        log.info("遍历解析路径，上传完成:{}", repoUrl);
//        return Response.<String>builder().code("0000").info("调用成功").build();
//    }

    // 优化
    @RequestMapping(value = "analyze_git_repository", method = RequestMethod.POST)
    @Override
    public Response<String> analyzeGitRepository(@RequestParam("repoUrl") String repoUrl, @RequestParam("userName") String userName, @RequestParam("token") String token) {
        Path tempDir = null;
        Git git = null;
        try {
            // 创建唯一临时目录
            tempDir = Files.createTempDirectory("git-clone-");
            String repoProjectName = extractProjectName(repoUrl);

            // 浅层克隆加速
            git = Git.cloneRepository()
                    .setURI(repoUrl)
                    .setDirectory(tempDir.toFile())
                    .setCredentialsProvider(new UsernamePasswordCredentialsProvider(userName, token))
                    .call();

            // 并行处理文件
            List<Document> allDocuments = new CopyOnWriteArrayList<>();
            try (Stream<Path> stream = Files.walk(tempDir)) {
                stream.parallel()
                        .filter(path -> path.toString().endsWith(".java"))
                        .forEach(path -> {
                            TikaDocumentReader reader = new TikaDocumentReader(new PathResource(path));
                            List<Document> docs = reader.get();
                            List<Document> splitDocs = tokenTextSplitter.apply(docs);
                            splitDocs.forEach(doc -> doc.getMetadata().put("knowledge", repoProjectName));
                            allDocuments.addAll(splitDocs);
                        });
            }

            // 批量写入向量库
            if (!allDocuments.isEmpty()) {
                pgVectorStore.accept(allDocuments);
            }

            // 更新Redis
            RList<String> elements = redissonClient.getList("ragTag");
            if (!elements.contains(repoProjectName)) {
                elements.add(repoProjectName);
            }

            return Response.<String>builder().code("0000").info("调用成功").build();
        } catch (Exception e) {
            log.error("分析仓库失败", e);
            throw new RuntimeException(e);
        } finally {
            // 清理资源
            if (git != null) {
                git.close();
            }
            if (tempDir != null) {
                FileUtils.deleteQuietly(tempDir.toFile());
            }
        }
    }


    // 提取项目名
    private String extractProjectName(String repoUrl) {
        String[] parts = repoUrl.split("/");
        String projectNameWithGit = parts[parts.length - 1];
        return projectNameWithGit.replace(".git", "");
    }
}
